package ModelMulti;


import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import Contoller.Main;



public class MonteCarloCalMultiThread extends Thread implements Runnable{
	
	
	private double Resutl;
	private int count=0;
	private double Time;
	private double Sum;
	private final Integer nb_coeur = Runtime.getRuntime().availableProcessors();;
	final double blockingCoefficient = 0.9;//a modifier celon l'utilisation de ressource externe élévé si besoin de ressource ext
	final int poolSize = (int)(nb_coeur / (1-blockingCoefficient));//calcule du nombre de mutlithread simu
	
	
	public MonteCarloCalMultiThread(final String CallPutFlag,final double S,final double T,final double r,final double b, final double v
			,final Integer nSteps, final Integer nSimulation,final double X) throws InterruptedException, ExecutionException
	{
	
		long start = System.currentTimeMillis();
		int z = 1;
		
		//initialisation de la liste des callable : fonction qui sera appeler par le multithread (call)
		final List<Callable<Double>> partitions = new ArrayList<Callable<Double>>();
		
		//on mets le nombre de thread a executer 
		 for(int d=0;d<nSimulation;d++) 
		    {
	 			partitions.add(new Callable<Double>() 
		    	{
		    		 public Double call() throws Exception
		    		 {
		    		
		    			 return thread_2(CallPutFlag,S,T,r,b, v
		    						,nSteps,nSimulation,X);
    			
		    		 }       
		    	});
		    }
		 //fixe le nombre de multithread
		final ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);
		//on réalise le multithreading
		List<Future<Double>> valueOfStocks = executorPool.invokeAll(partitions);
		
		//récupération des valeurs pour la dernière partie
		for(Future<Double> valueOfAStock : valueOfStocks)
		{
		
			this.Sum=this.Sum + Math.max(z*(valueOfAStock.get()-X),0);
			
		}
		
		//recupération resultat
		this.setResutl(java.lang.Math.exp((-r) * T)*(this.Sum/nSimulation));
	
		//recupération temps d'exec
		this.Time=System.currentTimeMillis()-start;
		
	}
	
	
	
	public double thread_2(String CallPutFlag,double St,double T,double r,double b, double v
			,Integer nSteps, Integer nSimulation,double X) 
	{	//on définit les variables locals pour évitez d'utiliser le synchronise qui ralentirai tous les threads
		Random rand = new Random() ;
		double dt = T / nSteps;
		double Drift = (b - (v*v) / 2) * dt;
		double vSqrdt = v * Math.sqrt(dt);
		this.count++;
		//bar de progression
		Main.GUI.jProgressBar1.setValue(this.count);
		
			//Calcul de st
			for(int j=1;j<=nSteps;j++)
			{
			
		    St= St * java.lang.Math.exp(Drift + vSqrdt * rand.nextGaussian());
			
			}
			
			//retour valeurs
			return  St;
	}
	
	

	public double getResutl() {
		return Resutl;
	}

	private void setResutl(double resutl) {
		Resutl = resutl;
	}

	public double getTime() {
		return Time;
	}
}
